﻿using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using DimensionsHelper.LanguageService.Syntax;

namespace DimensionsHelper.LanguageService.Symbols;

// +-------------+--------------------------------------------------------------------------------------+
// | Subtype     | Description                                                                          |
// |-------------+--------------------------------------------------------------------------------------|
// | None        | Used to indicate a null or empty variable.                                           |
// |             | In Visual Basic, this is an unassigned Variant or a variant assigned Empty.          |
// +-------------+--------------------------------------------------------------------------------------+
// | Double      | A 64-bit floating point number with at least 15 digits of precision,                 |
// |             | in the range -1.79769313486232E308 to -4.94065645841247E-324 for negative values and |
// |             | 4.94065645841247E-324 to 1.79769313486232E308 for positive values.                   |
// |             | In Visual Basic, this is a Double.                                                   |
// +-------------+--------------------------------------------------------------------------------------+
// | Long        | A 32-bit signed integer in the range -2,147,483,648 to 2,147,483,647.                |
// |             | In Visual Basic, this is a Long.                                                     |
// +-------------+--------------------------------------------------------------------------------------+
// | Text        | Contains a variable-length string that in theory can be up to approximately 2        |
// |             | billion characters in length. In Visual Basic, this is a String.                     |
// +-------------+--------------------------------------------------------------------------------------+
// | Categorical | A single or multiple categorical response type. The maximum number of responses is   |
// |             | theoretically approximately 4 billion. In Visual Basic, this is an array of Variants.|
// |             | Each variant must contain a Long value that corresponds to the unique category value.|
// +-------------+--------------------------------------------------------------------------------------+
// | Date        | An IEEE 64-bit (8-byte) floating-point number that represents a date in the range    |
// |             | from 1 January 100 to 31 December 9999 and a time in the range from                  |
// |             | 0:00:00 to 23:59:59.                                                                 |
// +-------------+--------------------------------------------------------------------------------------+
// | Object      | Contains an object.                                                                  |
// +-------------+--------------------------------------------------------------------------------------+
// | Boolean     | A Boolean value of either True or False.                                             |
// +-------------+--------------------------------------------------------------------------------------+


/// <summary>
///     值类型符号，指的是语法中的预定义类型，string、bool、long、categorical这种
///     基础的值类型。
/// </summary>
public sealed class ValueTypeSymbol : AbstractSymbol, ITypeSymbol
{
    private ValueTypeSymbol(string name) : base(SymbolKinds.NamedType)
    {
        Name = name;
    }

    /// <summary>
    ///     Void类型，用于无返回值的函数
    /// </summary>
    public static ValueTypeSymbol Void { get; } = new("Void");


    /// <summary>
    ///     任意类型
    /// </summary>
    public static ValueTypeSymbol Any { get; } = new("Any");


    /// <summary>
    ///     Null 值类型
    /// </summary>
    public static ValueTypeSymbol Null { get; } = new("Null");


    /// <summary>
    ///     Long 值类型
    /// </summary>
    public static ValueTypeSymbol Long { get; } = new("Long");


    /// <summary>
    ///     Double 值类型
    /// </summary>
    public static ValueTypeSymbol Double { get; } = new("Double");


    /// <summary>
    ///     String 值类型
    /// </summary>
    public static ValueTypeSymbol String { get; } = new("String");


    /// <summary>
    ///     Categorical 值类型
    /// </summary>
    public static ValueTypeSymbol Categorical { get; } = new("Categorical");


    /// <summary>
    ///     Boolean 值类型
    /// </summary>
    public static ValueTypeSymbol Boolean { get; } = new("Boolean");


    /// <summary>
    ///     Date 值类型
    /// </summary>
    public static ValueTypeSymbol Date { get; } = new("Date");


    public TypeKinds TypeKind => TypeKinds.ValueType;


    /// <summary>
    ///     值类型符号不支持此属性。
    /// </summary>
    public IDeclaration? Declaration => null;


    /// <summary>
    ///     值类型符号没有基类，此属性将一直是 <see langword="null" />
    /// </summary>
    public ITypeSymbol? BaseType => null;


    /// <summary>
    ///     值类型不实现接口，此属性将一直是空列表
    /// </summary>
    public IReadOnlyList<ITypeSymbol> Interfaces => Array.Empty<ITypeSymbol>();


    /// <summary>
    ///     值类型符号不在任何模块内，此属性将一直是 <see langword="null" />
    /// </summary>
    public string? ContainingModuleName => null;


    /// <summary>
    ///     值类型符号不在任何模块内，此属性将一直是 <see langword="null" />
    /// </summary>
    public ISymbol? ContainingModule => null;


    /// <summary>
    ///     值类型符号此属性一直是 <see langword="true" />
    /// </summary>
    public override bool IsValueType => true;

    public bool IsUnion => false;

    public bool IsModule => false;

    public bool IsClass => false;

    public bool IsInterface => false;

    public bool IsEnum => false;

    public bool IsDefault => false;

    public bool IsReadOnly => false;

    public bool IsWriteOnly => false;

    public bool IsBindable => false;

    public override string Name { get; }

    public override string FullName => Name;

    public override ISymbol? ContainingSymbol => null;

    public override bool IsUndefined => false;

    public override bool IsMacro => false;

    public override bool IsArray => false;

    public override bool IsFunction => false;

    public override bool IsProperty => false;

    public override bool IsMethod => false;

    public override bool IsParameter => false;

    public override bool IsMetadata => false;

    public override bool IsMetadataElement => false;

    public bool WithParameter => false;

    public bool WithConstant => false;

    public override bool CanBeDerived => false;

    public override bool CanMakeArray => true;


    public ITypeSymbol MakeArrayType(int rank, int[]? boundaries)
    {
        return new ArrayTypeSymbol(this, rank, boundaries);
    }


    public bool IsSignature => false;

    public ImmutableArray<ISymbol> GetMembers()
    {
        return ImmutableArray<ISymbol>.Empty;
    }


    public ITypeSymbol? LookupNamedMember(string name)
    {
        return null;
    }


    public override bool IsDeclared(string fileName, int position)
    {
        return true;
    }


    public override bool IsDeclared(string fileName)
    {
        return true;
    }


    public override bool Redeclare(ISymbol symbol)
    {
        return false;
    }


    public override void Reference(in SyntaxLocation location)
    {
    }

    public ITypeSymbol? GetDefaultProperty()
    {
        return null;
    }

    public ITypeSymbol? GetDefaultMethod()
    {
        return null;
    }

    public ITypeSymbol? GetIndexer()
    {
        return null;
    }

    public bool IsAssignableFrom(ITypeSymbol type)
    {
        if (ReferenceEquals(this, type))
        {
            return true;
        }

        if (ReferenceEquals(type, Void) || this == Void)
        {
            return false;
        }

        if (this == Any || this == Boolean /* 任何非空的类型值都是true */)
        {
            return true;
        }

        // Long和枚举类型可以相互赋值
        if (this == Long && type.IsEnum)
        {
            return true;
        }

        // Long可以赋值给Double和Date
        if (this == Double && (ReferenceEquals(type, Long) || ReferenceEquals(type, Date)))
        {
            return true;
        }

        // Date可以赋值给Long、Double
        if (this == Date && (ReferenceEquals(type, Long) || ReferenceEquals(type, Double)))
        {
            return true;
        }

        // Null 可以赋值给任何类型
        return this == Null || ReferenceEquals(type, Null);
    }


    public bool HasInterface(ITypeSymbol symbol)
    {
        return false;
    }


    /// <summary>
    ///     如果给定的类型符号是数值类型，返回<see langword="true" />。
    /// </summary>
    /// <param name="typeSymbol">待检查的类型符号</param>
    public static bool IsNumberType(ITypeSymbol typeSymbol)
    {
        return ReferenceEquals(typeSymbol, Long) || ReferenceEquals(typeSymbol, Double) ||
               ReferenceEquals(typeSymbol, Date) || ReferenceEquals(typeSymbol, Boolean);
    }


    /// <summary>
    ///     如果给定类型符号是<see cref="Void" />，返回<see langword="true" />。
    /// </summary>
    /// <param name="typeSymbol">给定符号</param>
    public static bool IsVoid(ITypeSymbol typeSymbol)
    {
        return ReferenceEquals(typeSymbol, Void);
    }


    /// <summary>
    ///     如果给定类型符号是<see cref="Long" />，返回<see langword="true" />。
    /// </summary>
    /// <param name="typeSymbol">给定符号</param>
    public static bool IsLong(ITypeSymbol typeSymbol)
    {
        return ReferenceEquals(typeSymbol, Long);
    }

    
    /// <summary>
    ///     如果给定类型符号是<see cref="Double" />，返回<see langword="true" />。
    /// </summary>
    /// <param name="typeSymbol">给定符号</param>
    public static bool IsDouble(ITypeSymbol typeSymbol)
    {
        return ReferenceEquals(typeSymbol, Double);
    }


    /// <summary>
    ///     如果给定类型符号是<see cref="Null" />，返回<see langword="true" />。
    /// </summary>
    /// <param name="typeSymbol">给定符号</param>
    public static bool IsNull(ITypeSymbol typeSymbol)
    {
        return ReferenceEquals(typeSymbol, Null);
    }


    /// <summary>
    ///     如果给定类型符号是<see cref="Null" />或<see cref="Any" />，返回<see langword="true" />。
    /// </summary>
    /// <param name="typeSymbol">给定符号</param>
    public static bool IsAnyOrNull(ITypeSymbol typeSymbol)
    {
        return ReferenceEquals(typeSymbol, Null) || ReferenceEquals(typeSymbol, Any);
    }


    /// <summary>
    ///     如果给定类型符号是<see cref="String" />，返回<see langword="true" />。
    /// </summary>
    /// <param name="typeSymbol">给定符号</param>
    public static bool IsString(ITypeSymbol typeSymbol)
    {
        return ReferenceEquals(typeSymbol, String);
    }


    /// <summary>
    ///     如果给定类型符号是<see cref="CategoricalLiteral"/>，返回<see langword="true"/>
    /// </summary>
    /// <param name="typeSymbol">给定符号</param>
    public static bool IsCategorical(ITypeSymbol typeSymbol)
    {
        return ReferenceEquals(typeSymbol, Categorical);
    }


    public static bool TryGetValueSymbol(string typeName, [MaybeNullWhen(false)] out ValueTypeSymbol symbol)
    {
        symbol = typeName.ToLower() switch
        {
            "void" => Void,
            "any" => Any,
            "null" => Null,
            "long" => Long,
            "double" => Double,
            "string" => String,
            "categorical" => Categorical,
            "boolean" => Boolean,
            "date" => Date,
            _ => null
        };

        return symbol != null;
    }

    public static bool TryGetValueSymbol(SyntaxKinds kind, [MaybeNullWhen(false)] out ValueTypeSymbol symbol)
    {
        symbol = kind switch
        {
            SyntaxKinds.String => String,
            SyntaxKinds.Boolean => Boolean,
            SyntaxKinds.Integer => Long,
            SyntaxKinds.Double => Double,
            SyntaxKinds.Categorical => Categorical,
            SyntaxKinds.Null => Null,
            _ => null
        };

        return symbol != null;
    }
}